﻿namespace nCodeGeneratingTool
{
    using System;
    using System.Collections.Generic;
    using System.Globalization;
    using System.Xml;
    using System.Xml.XPath;

    public class XMLCommonOperations
    {
        #region Fields

        /// <summary>
        /// The invoice
        /// </summary>
        readonly XmlDocument document;

        /// <summary>
        /// The root navigator for the XML document.
        /// </summary>
        readonly XPathNavigator navigator;

        /// <summary>
        /// The XML file name
        /// </summary>
        readonly string XmlFileName;

        #endregion Fields

        #region Constructors

        /// <summary>
        /// Initializes a new instance of the <see cref="XMLCommonOperations"/> class.
        /// </summary>
        /// <param name="filename">The filename.</param>
        /// <param name="rootElement">The root element.</param>
        public XMLCommonOperations(string filename, string rootElement)
        {
            //bool FileInUse = CheckFileInUse(filename, out Status);
            //if (!FileInUse)
            //{
            if (!System.IO.File.Exists(filename))
            {
                this.document = new XmlDocument();

                XmlDeclaration xmlDeclaration = this.document.CreateXmlDeclaration("1.0", "utf-8", null);

                // Create the root element
                XmlElement rootNode = this.document.CreateElement(rootElement);
                this.document.InsertBefore(xmlDeclaration, this.document.DocumentElement);
                this.document.AppendChild(rootNode);

                this.document.Save(filename);
            }
            this.XmlFileName = filename;
            this.document = new XmlDocument();

            System.IO.FileInfo fi = new System.IO.FileInfo(filename);
            int iterate = 0;
            while (IsFileLocked(fi) && iterate < 5)
            {
                System.Threading.Thread.Sleep(100);
                iterate++;
            }
            this.document.Load(filename);
            this.navigator = this.document.CreateNavigator();
            //}
        }

        #endregion Constructors

        #region Methods

        /// <summary>
        /// Selects a subtree in the XML data.
        /// </summary>
        /// <param name="path">The path.</param>
        /// <param name="attributeName">Name of the attribute.</param>
        /// <param name="attributeValue">The attribute value.</param>
        /// <returns>XPathNavigator.</returns>
        public XPathNavigator CreateAndSelectAttribute(string path, string attributeName, string attributeValue)
        {
            XPathNodeIterator iter = this.navigator.Select(path);
            iter.MoveNext();
            iter.Current.CreateAttribute(attributeName, attributeName, iter.Current.NamespaceURI, attributeValue);
            return iter.Current;
        }

        /// <summary>
        /// Selects a subtree in the XML data.
        /// </summary>
        /// <param name="parentPath">The parent path.</param>
        /// <param name="childName">Name of the child.</param>
        /// <param name="childValue">The child value.</param>
        /// <returns>XPathNavigator.</returns>
        public XPathNavigator CreateAndSelectElement(string parentPath, string childName, string childValue)
        {
            XPathNodeIterator iter = this.navigator.Select(parentPath);
            iter.MoveNext();
            if (childValue == "")
                iter.Current.AppendChild("<" + childName + "/>");
            else
                iter.Current.AppendChild("<" + childName + ">" + childValue + "</" + childName + ">");
            return iter.Current.SelectChildren(XPathNodeType.Element).Current;
        }

        /// <summary>
        /// Deletes the element or attribute.
        /// </summary>
        /// <param name="path">The path.</param>
        /// <returns><c>true</c> if XXXX, <c>false</c> otherwise.</returns>
        public bool DeleteElementOrAttribute(string path)
        {
            XPathNodeIterator iter = this.navigator.Select(path);
            iter.MoveNext();
            iter.Current.DeleteSelf();
            return true;
        }

        /// <summary>
        /// Gets the childrens.
        /// </summary>
        /// <param name="nav">The nav.</param>
        /// <param name="name">The name.</param>
        /// <returns>XPathNodeIterator.</returns>
        public XPathNodeIterator GetChildrens(XPathNavigator nav, string name)
        {
            //nav = nav.Clone();
            XPathNodeIterator iter = nav.Select(name);
            iter.MoveNext();
            return iter.Current.SelectChildren(XPathNodeType.All);
        }

        /// <summary>
        /// Gets an element value from the XML data.
        /// </summary>
        /// <param name="nav">The nav.</param>
        /// <param name="name">The name.</param>
        /// <param name="isAttribute">if set to <c>true</c> [is attribute].</param>
        /// <returns>System.String.</returns>
        public string GetValue(XPathNavigator nav, string name, bool isAttribute)
        {
            if (isAttribute)
            {
                XPathNodeIterator iter = nav.Select('@' + name);
                iter.MoveNext();
                return iter.Current.Value;
            }
            else
            {
                //nav = nav.Clone();
                XPathNodeIterator iter = nav.Select(name);
                iter.MoveNext();
                return iter.Current.Value;
            }
        }

        /// <summary>
        /// Gets an element value as double from the XML data.
        /// </summary>
        /// <param name="nav">The nav.</param>
        /// <param name="name">The name.</param>
        /// <returns>System.Double.</returns>
        public double GetValueAsDouble(XPathNavigator nav, string name)
        {
            try
            {
                string value = GetValue(nav, name, false);
                if (value.Length == 0)
                    return 0;
                return Double.Parse(value, CultureInfo.InvariantCulture);
            }
            catch (Exception ex)
            {
                //ex.Log();
                //Debug.WriteLine(ex.Message);
            }
            return 0;
        }

        /// <summary>
        /// Sets an element value from the XML data.
        /// </summary>
        /// <param name="nav">The nav.</param>
        /// <param name="name">The name.</param>
        /// <returns><c>true</c> if [is item exist] [the specified nav]; otherwise, <c>false</c>.</returns>
        public bool IsItemExist(XPathNavigator nav, string name)
        {
            XPathNodeIterator iter = nav.Select(name);
            iter.MoveNext();
            if (iter.CurrentPosition == 0)
                return false;
            else
                return true;
        }

        /// <summary>
        /// Saves this instance.
        /// </summary>
        public void Save()
        {
            this.document.Save(this.XmlFileName);
        }

        /// <summary>
        /// Selects a subtree in the XML data.
        /// </summary>
        /// <param name="path">The path.</param>
        /// <returns>XPathNavigator.</returns>
        public XPathNavigator SelectItem(string path)
        {
            XPathNodeIterator iter = this.navigator.Select(path);
            iter.MoveNext();
            return iter.Current;
        }

        /// <summary>
        /// Sets an element value from the XML data.
        /// </summary>
        /// <param name="nav">The nav.</param>
        /// <param name="name">The name.</param>
        /// <param name="valueToSet">The value to set.</param>
        /// <returns>System.String.</returns>
        public string UpdateValue(XPathNavigator nav, string name, string valueToSet)
        {
            XPathNodeIterator iter = nav.Select(name);
            iter.MoveNext();
            iter.Current.SetValue(valueToSet);
            return iter.Current.Value;
        }

        protected virtual bool IsFileLocked(System.IO.FileInfo file)
        {
            System.IO.FileStream stream = null;

            try
            {
                stream = file.Open(System.IO.FileMode.Open, System.IO.FileAccess.ReadWrite, System.IO.FileShare.None);
            }
            catch (System.IO.IOException)
            {
                //the file is unavailable because it is:
                //still being written to
                //or being processed by another thread
                //or does not exist (has already been processed)
                return true;
            }
            finally
            {
                if (stream != null)
                    stream.Close();
            }

            //file is not locked
            return false;
        }

        #endregion Methods

        #region Other

        //private bool CheckFileInUse(string filename, out string Status)
        //{
        //    string[] folders = System.IO.Path.GetDirectoryName(filename).Split(System.IO.Path.DirectorySeparatorChar);
        //    string[] patientFolder = folders[folders.Length - 1].Split('_');
        //    int patientId;
        //    Int32.TryParse(patientFolder[1], out patientId);
        //    //if(patientId > 0)
        //    //{
        //    string ip = IPAddressOperation.GetIPv4Address();
        //    SQLDataLayer.SQLOperations.CommonFunctions function = new CommonFunctions();
        //    return function.IsAnyOneUsingFile(patientId, ip, out Status);
        //    //Check wether anyone using this file or not ?
        //    //If it is using
        //    //      then check whether last access is later then 7 Minutes ?
        //    //      if yes
        //    //             Update database entry.
        //    //             Allow access
        //    //      if not
        //    //              Send Out message
        //    //If not using
        //    //      Update Database Entry.
        //    //      Allow Access
        //}
        //internal bool ClearPatientInUse()
        //{
        //    string[] folders = System.IO.Path.GetDirectoryName(XmlFileName).Split(System.IO.Path.DirectorySeparatorChar);
        //    string[] patientFolder = folders[folders.Length - 1].Split('_');
        //    int patientId;
        //    Int32.TryParse(patientFolder[1], out patientId);
        //    string ip = IPAddressOperation.GetIPv4Address();
        //    SQLDataLayer.SQLOperations.CommonFunctions function = new CommonFunctions();
        //    return function.ClearPatientInUse(patientId, ip);
        //}

        #endregion Other
    }

    public class XMLProperties
    {
        #region Fields

        private Dictionary<string, string> _Properties;

        #endregion Fields

        #region Constructors

        public XMLProperties(string FilePath)
        {
            string rootElement = "NCodeConfiguration";
            XMLCommonOperations xmlCommonOperations = new XMLCommonOperations(FilePath, rootElement);
            XPathNavigator navigator = xmlCommonOperations.SelectItem("NCodeConfiguration");
            XPathNodeIterator childIterator = xmlCommonOperations.GetChildrens(navigator, rootElement);
            Properties = new Dictionary<string, string>();
            while (childIterator.MoveNext())
            {
                Properties.Add(childIterator.Current.GetAttribute("Name", "").ToString(), childIterator.Current.GetAttribute("Value", "").ToString());
            }
        }

        #endregion Constructors

        #region Properties

        public Dictionary<string, string> Properties
        {
            get
            {
                if (_Properties == null)
                {
                    _Properties = new Dictionary<string, string>();
                }
                return _Properties;
            }
            set
            {
                _Properties = value;
            }
        }

        #endregion Properties
    }
}